home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 June: Reference Library / Dev.CD Jun 96 RL / Dev.CD Jun 96 RL.toast / Technical Documentation / develop / develop Issue 26 / develop Issue 26 code / Truffles - Display Mgr. / Sprocket / Sources / Window.cp < prev   
Encoding:
Text File  |  1996-01-02  |  25.7 KB  |  1,083 lines  |  [TEXT/MMCC]

  1. /*
  2.     File:        Window.cp
  3.  
  4.     Contains:    Implementation of TWindow, a base class which provides a
  5.                 framework for building way-cool windows which even John
  6.                 Sullivan would be happy with. Floating windows and “smart
  7.                 zooming” algorithms are based on code samples provided by
  8.                 Dean Yu. Tim Craycroft, the guy making the window manager
  9.                 do all this work for you has also been a great help.
  10.                 
  11.     Written by: Dave Falkenburg
  12.  
  13.     Copyright:    © 1993-1995 by Dave Falkenburg, all rights reserved.
  14.  
  15.     Change History (most recent first):
  16.     
  17.         <14>     1/24/95    DRF        DoMenuSelection now returns a Boolean. Added some default
  18.                                     behavior for handling the close menu item-- this will change
  19.                                     when we make some things recordable.
  20.         <13>     1/20/95    DRF        Fix the “calling DisposeWindow on DialogPtr” problem reported by
  21.                                     Gary Powell @ Adobe by adding a cheezy flag that TWindow
  22.                                     initializes, but TDialogWindow slams. In TWindow::Close, we
  23.                                     check this flag and call DisposeDialog instead of DisposeWindow,
  24.                                     surely preventing memory leaks for complex dialogs.
  25.         <12>      1/3/95    DRF        Add Nitin’s changes for Drag handling: a ClickAndDrag method.
  26.         <11>      1/3/95    DRF        DoMenuCommand now returns a Boolean. Also got rid of
  27.                                     conditionals for ClipAbove: by the time this gets to print
  28.                                     everyone should be using Universal Headers 2.0.
  29.         <10>     12/6/94    DRF        Rolled in David Den Boer’s fixes. Also add the conditionals for
  30.                                     newest universal headers again.
  31.          <9>    11/23/94    DRF        Bite the bullet just require the latest universal headers
  32.          <8>    11/17/94    DRF        Add casts for CFront & PPCC. Also dealt with the change to
  33.                                     ClipAbove in the latest universal headers.
  34.          <7>    11/12/94    DRF        Added AdjustMenusBeforeMenuSelection.
  35.          <6>     11/8/94    DRF        Add some better menu handling methods.
  36.          <5>     9/27/94    DRF         AppLib.h is now Sprocket.h
  37.          <4>      9/9/94    DRF        Reorganized headers and removed redundant #includes.
  38.          <3>      9/4/94    DRF        Added DrawJustTheGrowIcon.
  39.          <2>     8/27/94    DRF        In TWindow::Close, call window’s (de)Activate method before
  40.                                     closing so that menus can be properly updated.
  41.     
  42.     To Do:        Make sure invisible windows can be created & managed
  43.                 Handle modal windows as another class of windows
  44.                 Fix activate bugs when showing and hiding windows
  45.                 Window positioning methods (getters and setters)
  46.                 Display Manager support
  47.                 Changes to support AEObject model
  48.  */
  49.  
  50. #include "Sprocket.h"
  51. #include "Window.h"
  52. #include "UtilityClasses.h"
  53.  
  54. #include <Script.h>        //    for GetMBarHeight()
  55. #include <LowMem.h>        //    for LMGetWindowList()
  56.  
  57.  
  58. UInt32                TWindow::fgModalState = 0;
  59.  
  60.  
  61. const WindowRef     kNoFloatingWindows        = (WindowRef) -1;
  62. const WindowRef        kNoModalWindows            = (WindowRef) -1;
  63.  
  64. const short            kScreenEdgeSlop            = 4;
  65. const short            kSpaceForFinderIcons    = 64;
  66. const short            kMinimumTitleBarHeight    = 21;
  67. const short            kMinimumWindowSize        = 32;
  68.  
  69.  
  70. static void            HiliteShowHideFloatingWindows(Boolean hiliting,Boolean hiding);
  71.  
  72. static void            FindScreenRectWithLargestPartOfWindow(WindowRef aWindow,Rect *theBestScreenRect, GDHandle * theBestDevice);
  73. static pascal void    CalculateWindowAreaOnDevice(short depth,short deviceFlags,GDHandle targetDevice,long userData);
  74.  
  75. struct    CalcWindowAreaDeviceLoopUserData
  76.     {
  77.     GDHandle    fScreenWithLargestPartOfWindow;
  78.     long        fLargestArea;
  79.     Rect        fWindowBounds;
  80.     };
  81.  
  82.  
  83.  
  84. TWindow::TWindow()
  85.     {
  86.     fIsDialogWindow = false;
  87.     }
  88.  
  89.  
  90. TWindow::~TWindow()
  91.     {
  92.     WindowRef    newFrontWindow = NULL;
  93.  
  94.     if (fWindow)
  95.         {
  96.         if (FrontNormalWindow() == fWindow)
  97.             newFrontWindow = GetNextWindow(fWindow);
  98.         
  99.         this->Activate(false);
  100.  
  101.         if (fIsDialogWindow)
  102.             DisposeDialog((DialogRef) fWindow);
  103.         else
  104.             DisposeWindow(fWindow);
  105.  
  106.         if (fWindowType == kModalWindow)
  107.             this->ExitModalState();
  108.         
  109.         if (newFrontWindow)
  110.             HiliteAndActivateWindow(newFrontWindow,true);
  111.         }
  112.     }
  113.  
  114.  
  115.  
  116. void
  117. TWindow::CreateWindow(WindowType typeOfWindowToCreate /* = kNormalWindow */)
  118.     {
  119.     WindowRef    behindWindow;
  120.     WindowRef    oldTopWindow = NULL;
  121.  
  122.     if (typeOfWindowToCreate == kNormalWindow)
  123.         {
  124.         //    normal windows are always created behind modal and floaters
  125.         
  126.         behindWindow = LastFloatingWindow();
  127.         oldTopWindow = FrontNormalWindow();
  128.         }
  129.     else if (typeOfWindowToCreate == kFloatingWindow)
  130.         {
  131.         //    always create floaters behind modal windows
  132.  
  133.         behindWindow = LastModalWindow();
  134.         oldTopWindow = FrontFloatingWindow();
  135.         }
  136.     else if (typeOfWindowToCreate == kModalWindow)
  137.         {
  138.         //    modal windows are always created frontmost
  139.  
  140.         behindWindow = (WindowRef) -1;
  141.         oldTopWindow = FrontModalWindow();
  142.  
  143.         this->EnterModalState();
  144.         }
  145.  
  146.  
  147.     fWindow = this->MakeNewWindow(behindWindow);
  148.  
  149.  
  150.     if (fWindow != NULL)
  151.         {
  152.         SetWRefCon(fWindow,(long) this);
  153.         fIsVisible = IsWindowVisible ( fWindow );
  154.         fWindowType = typeOfWindowToCreate;
  155.         SetWindowKind(fWindow,typeOfWindowToCreate);
  156.  
  157.         if ((fIsVisible) && (fgModalState == 0))
  158.             {
  159.             if (fWindowType == kNormalWindow)
  160.                 HiliteAndActivateWindow(oldTopWindow,false);
  161.  
  162.             else if (fWindowType == kFloatingWindow)
  163.                 HiliteAndActivateWindow(oldTopWindow,true);
  164.  
  165.             HiliteAndActivateWindow(fWindow,true);
  166.             }
  167.         }
  168.     else
  169.         {
  170.         if (fWindowType == kModalWindow)
  171.             this->ExitModalState();
  172.         }
  173.     }
  174.  
  175.  
  176. void
  177. TWindow::AdjustCursor(EventRecord * /* anEvent */)
  178.     {
  179.     }
  180.  
  181.  
  182. void
  183. TWindow::Idle(EventRecord * /* anEvent */)
  184.     {
  185.     }
  186.     
  187. void
  188. TWindow::Activate(Boolean /* activating */)
  189.     {
  190.     }
  191.     
  192. void
  193. TWindow::Draw(void)
  194.     {
  195.     }
  196.     
  197. void
  198. TWindow::Click(EventRecord * /* anEvent */)
  199.     {
  200.     }
  201.     
  202. void
  203. TWindow::KeyDown(EventRecord * /* anEvent */)
  204.     {
  205.     }
  206.  
  207.  
  208. void
  209. TWindow::Select(void)
  210.     {
  211.     WindowRef    oldTopWindow, behindWindow;
  212.     
  213.     if (fWindowType == kNormalWindow)
  214.         {
  215.         oldTopWindow = FrontNormalWindow();
  216.         behindWindow = LastFloatingWindow();
  217.         if (behindWindow == kNoFloatingWindows)
  218.             behindWindow = LastModalWindow();
  219.         }
  220.     else if (fWindowType == kFloatingWindow)
  221.         {
  222.         oldTopWindow = FrontFloatingWindow();
  223.         behindWindow = LastModalWindow();
  224.         }
  225.     else if (fWindowType == kModalWindow)
  226.         {
  227.         oldTopWindow = FrontModalWindow();
  228.         behindWindow = (WindowRef) -1;
  229.         }
  230.     
  231.     if (fWindow != oldTopWindow)
  232.         {
  233.         if (behindWindow == (WindowRef) -1)
  234.             SelectWindow(fWindow);
  235.         else
  236.             SendBehind(fWindow,behindWindow);
  237.  
  238.         if (oldTopWindow != NULL)
  239.             {
  240.             if (fWindowType == kFloatingWindow)
  241.                 HiliteWindow(oldTopWindow,true);
  242.             else
  243.                 HiliteAndActivateWindow(oldTopWindow,false);
  244.             }
  245.  
  246.         HiliteAndActivateWindow(fWindow,true);
  247.         }
  248.     }
  249.  
  250.  
  251. void
  252. TWindow::Drag(Point startPoint)
  253.     {
  254.     GrafPtr        savePort;
  255.     KeyMap        theKeyMap;
  256.     Boolean        commandKeyDown = false;
  257.     long        dragResult;
  258.     
  259.     if (WaitMouseUp())        //    de-bounce?
  260.         {
  261.         // Set up the Window Manager port.
  262.     
  263.         GetPort(&savePort);
  264.         SetPort(gWindowManagerPort);
  265.         SetClip(GetGrayRgn());
  266.  
  267.         // Check to see if the command key is down.
  268.     
  269.         GetKeys(theKeyMap);
  270.         commandKeyDown = ((theKeyMap[1] & 0x8000) != 0);
  271.         
  272.         if (commandKeyDown)
  273.             {
  274.             //    We’re not going to change window ordering,
  275.             //    so make sure that we don’t drag in front of
  276.             //    other windows which may be in front of ours.
  277.  
  278.             ClipAbove(fWindow);
  279.             }
  280.         else if (fWindowType != kFloatingWindow)
  281.             {
  282.             //    We’re dragging a normal window, so make sure
  283.             //    that we don’t drag in front of any floating
  284.             //    windows.
  285.  
  286.             ClipAbove(FrontNormalWindow());
  287.             }
  288.  
  289.         //    Drag an outline of the window around the desktop.
  290.         //    NOTE: DragGrayRgn destroys the region passed in, so make a copy
  291.  
  292.         RgnHandle    tempRgn = NewRgn();
  293.  
  294.         GetWindowStructureRgn(fWindow, tempRgn);
  295.         dragResult = DragGrayRgn(tempRgn, startPoint, &gDeskRectangle, &gDeskRectangle, noConstraint, nil);
  296.  
  297.         DisposeRgn(tempRgn);    
  298.  
  299.         SetPort(savePort);    //    Get back to old port
  300.  
  301.         if ((dragResult != 0) && (dragResult != 0x80008000))
  302.             this->Nudge((short) (dragResult & 0xFFFF),(short) (dragResult >> 16));
  303.         }
  304.  
  305.     if (!commandKeyDown)
  306.         this->Select();
  307.     }
  308.  
  309.  
  310. void
  311. TWindow::Nudge(short horizontalDistance, short verticalDistance)
  312.     {
  313.     short        newHorizontalPosition, newVerticalPosition;
  314.     RgnHandle    tempRgn = NewRgn ();
  315.  
  316.     GetWindowContentRgn ( fWindow, tempRgn );
  317.     newHorizontalPosition = (short) (**tempRgn).rgnBBox.left + horizontalDistance;
  318.     newVerticalPosition   = (short) (**tempRgn).rgnBBox.top  + verticalDistance;
  319.     DisposeRgn ( tempRgn );
  320.  
  321.     MoveWindow(fWindow,newHorizontalPosition,newVerticalPosition,false);
  322.     }
  323.  
  324.  
  325. void
  326. TWindow::Grow(Point startPoint)
  327.     {
  328.     GrafPtr    oldPort;
  329.     long    newSize;
  330.     Rect    oldWindowRect,resizeLimits;
  331.     
  332.     GetPort(&oldPort);
  333.     
  334.     GetWindowSizeLimits(&resizeLimits);
  335.     newSize = GrowWindow(fWindow,startPoint,&resizeLimits);
  336.     if (newSize)
  337.         {
  338.         oldWindowRect = GetWindowPort ( fWindow )->portRect;
  339.         SizeWindow ( fWindow, (short) newSize, (short) (newSize >> 16), true );
  340.         SetPortWindowPort ( fWindow );
  341.         resizeLimits = GetWindowPort ( fWindow )->portRect;
  342.         this->AdjustForNewWindowSize(&oldWindowRect,&resizeLimits);
  343.         }
  344.     
  345.     SetPort(oldPort);
  346.     }
  347.  
  348.  
  349. void
  350. TWindow::Zoom(short zoomState)
  351.     {
  352.     GrafPtr        oldPort;
  353.     FontInfo    systemFontInfo;
  354.     short        titleBarHeight;
  355.     Rect        bestScreenRect,perfectWindowRect,scratchRect;
  356.     short        amountOffscreen;
  357. //    WindowPeek    windowAsWindowPeek = (WindowPeek) fWindow;
  358.     GDHandle    bestDevice;
  359.     
  360.     GetPort(&oldPort);
  361.  
  362.     //    Figure out the height of the title bar so we can properly position
  363.     //    a window. The algorithm is stolen from the System 7.x 'WDEF' (0)
  364.     //
  365.     //    This probably isn’t the best thing to do: A better way might be 
  366.     //    to diff the structure and content region rectangles?
  367.  
  368.     SetPort(gWindowManagerPort);
  369.     GetFontInfo(&systemFontInfo);
  370.     titleBarHeight = (short) (systemFontInfo.ascent + systemFontInfo.descent + 4);
  371.     if ((titleBarHeight % 2) == 1)
  372.         titleBarHeight--;
  373.     if (titleBarHeight < kMinimumTitleBarHeight)
  374.         titleBarHeight = kMinimumTitleBarHeight;
  375.  
  376.  
  377.     //    Only do the voodoo magic if we are really “zooming” the window.
  378.  
  379.     if (zoomState == inZoomOut)
  380.         {
  381.         FindScreenRectWithLargestPartOfWindow(fWindow,&bestScreenRect,&bestDevice);
  382.         bestScreenRect.top += titleBarHeight;
  383.  
  384.         this->GetPerfectWindowSize(&perfectWindowRect);
  385.         OffsetRect(&perfectWindowRect,-perfectWindowRect.left,-perfectWindowRect.top);
  386.  
  387.         //    Take the zero-pined perfect window size and move it to
  388.         //    the top left of the    window’s content region.
  389.  
  390.         RgnHandle    tempRgn = NewRgn ();
  391.         GetWindowContentRgn ( fWindow, tempRgn );
  392.         OffsetRect ( &perfectWindowRect,
  393.                             (**tempRgn).rgnBBox.left, (**tempRgn).rgnBBox.top );
  394.         DisposeRgn ( tempRgn );
  395.  
  396.  
  397.         //    Does perfectWindowRect fit completely on the best screen?
  398.         
  399.         SectRect(&perfectWindowRect, &bestScreenRect, &scratchRect);
  400.         if (!EqualRect(&perfectWindowRect, &scratchRect))
  401.             {
  402.             //    SectRect sez perfectWindowRect doesn’t completely fit
  403.             //    on the screen, so bump the window so that more of it fits.
  404.  
  405.             //    Make sure that the left edge of perfectWindowRect is forced
  406.             //    onto the best screen.  This is in case we are bumping
  407.             //    the window to the right.
  408.  
  409.             amountOffscreen = bestScreenRect.left - perfectWindowRect.left;
  410.             if (amountOffscreen > 0)
  411.                 {
  412.                 perfectWindowRect.left += amountOffscreen;
  413.                 perfectWindowRect.right += amountOffscreen;
  414.                 }
  415.  
  416.             //    Make sure that the left edge of perfectWindowRect is forced
  417.             //    onto the best screen.  This is in case we are bumping
  418.             //    the window downward to a new screen.
  419.     
  420.             amountOffscreen = bestScreenRect.top - perfectWindowRect.top;
  421.             if (amountOffscreen > 0)
  422.                 {
  423.                 perfectWindowRect.top += amountOffscreen;
  424.                 perfectWindowRect.bottom += amountOffscreen;
  425.                 }
  426.  
  427.             //    If right edge of window falls off the screen,
  428.             //        Move window to the left until the right edge IS on the screen
  429.             //        OR the left edge is at bestScreenRect.left
  430.  
  431.             amountOffscreen = perfectWindowRect.right - bestScreenRect.right;
  432.             if (amountOffscreen > 0)
  433.                 {
  434.                 //    Are we going to push the left edge offscreen? If so, change the
  435.                 //    offset so we move the window all the way over to the left.
  436.                 
  437.                 if ((perfectWindowRect.left - amountOffscreen) < bestScreenRect.left)
  438.                     amountOffscreen = perfectWindowRect.left - bestScreenRect.left;
  439.  
  440.                 perfectWindowRect.left -= amountOffscreen;
  441.                 perfectWindowRect.right -= amountOffscreen;
  442.                 }
  443.  
  444.             //    If bottom edge of window falls off the screen,
  445.             //        Move window to up until the bottom edge IS on the screen
  446.             //        OR the top edge is at bestScreenRect.top
  447.  
  448.             amountOffscreen = perfectWindowRect.bottom - bestScreenRect.bottom;
  449.             if (amountOffscreen > 0)
  450.                 {
  451.                 //    Are we going to push the top edge offscreen? If so, change the
  452.                 //    offset so we move the window just to the top.
  453.                 
  454.                 if ((perfectWindowRect.top - amountOffscreen) < bestScreenRect.top)
  455.                     amountOffscreen = perfectWindowRect.top - bestScreenRect.top;
  456.  
  457.                 perfectWindowRect.top -= amountOffscreen;
  458.                 perfectWindowRect.bottom -= amountOffscreen;
  459.                 }
  460.  
  461.             SectRect(&perfectWindowRect, &bestScreenRect, &scratchRect);
  462.             if (!EqualRect(&perfectWindowRect, &scratchRect))
  463.                 {
  464.                 //    The edges of the window still fall offscreen,
  465.                 //    so make the window smaller until it fits.
  466.                 
  467.                 if (perfectWindowRect.bottom > bestScreenRect.bottom)
  468.                     perfectWindowRect.bottom = bestScreenRect.bottom;
  469.  
  470.                 //    If the right edge is still falling off,
  471.                 //        save space for Finder’s disk icons as well.
  472.  
  473.                 if (perfectWindowRect.right > bestScreenRect.right)
  474.                     {
  475.                     perfectWindowRect.right = bestScreenRect.right;
  476.                     
  477.                     //    If we were on the main screen, leave room for Finder icons, too.
  478.                     
  479.                     if (bestDevice == GetMainDevice())
  480.                         perfectWindowRect.right -= kSpaceForFinderIcons;
  481.                     }
  482.                 }
  483.             }
  484.  
  485.         //    Stash our new rectangle inside of the Window’s dataHandle
  486.         //    so that ZoomWindow does the right thing.
  487.         
  488.     //    (**((WStateDataHandle) (windowAsWindowPeek->dataHandle))).stdState = perfectWindowRect;
  489.         SetWindowStandardState ( fWindow, &perfectWindowRect );
  490.         }
  491.  
  492.     //    HEY YOU! Don’t forget to set the port to the window being zoomed
  493.     //    Why, you ask? Because IM-IV-50 says to; otherwise you die
  494.     
  495.     SetPortWindowPort ( fWindow );
  496.  
  497.     Rect    oldWindowRect = GetWindowPort ( fWindow )->portRect;    
  498.     ZoomWindow(fWindow,zoomState,false);
  499.     Rect    newWindowRect = GetWindowPort ( fWindow )->portRect;
  500.     this->AdjustForNewWindowSize(&oldWindowRect,&newWindowRect);
  501.  
  502.     SetPort(oldPort);
  503.     }
  504.  
  505. void
  506. TWindow::ShowHide(Boolean showFlag)
  507.     {
  508.     //    Here we need the “::” in front of ShowHide to indicate we are calling
  509.     //    the global function, and not the method ShowHide. Unintended recursion
  510.     //    can do bad things to the unsuspecting programmer.
  511.     
  512.     //    Some C++ programmers would always prepend the “::” on function calls.
  513.     
  514.     ::ShowHide(fWindow,showFlag);
  515.     fIsVisible = showFlag;
  516.     }
  517.     
  518.  
  519. Boolean
  520. TWindow::EventFilter(EventRecord * /* theEvent */)
  521.     {
  522.     return false;
  523.     }
  524.     
  525.  
  526. void
  527. TWindow::GetPerfectWindowSize(Rect *perfectSize)
  528.     {
  529.     *perfectSize = qd.screenBits.bounds;
  530.     }
  531.  
  532.  
  533. void
  534. TWindow::GetWindowSizeLimits(Rect *limits)
  535.     {
  536.     limits->top = limits->left = kMinimumWindowSize;
  537.     limits->right = gDeskRectangle.right - gDeskRectangle.left;
  538.     limits->bottom = gDeskRectangle.bottom - gDeskRectangle.top;
  539.     }
  540.  
  541.  
  542. void
  543. TWindow::AdjustForNewWindowSize(Rect * /* oldRect */, Rect * /* newSize */)
  544.     {
  545.     }
  546.  
  547.  
  548. Boolean
  549. TWindow::IsVisible(void)
  550.     {
  551.     return fIsVisible;
  552.     }
  553.  
  554.  
  555. Boolean
  556. TWindow::CanClose(void)
  557.     {
  558.     return true;
  559.     }
  560.  
  561.  
  562. Boolean
  563. TWindow::Close(void)
  564.     {
  565.     delete this;
  566.     return true;
  567.     }
  568.  
  569.  
  570. void
  571. TWindow::AdjustMenusBeforeMenuSelection(void)
  572.     {
  573.     }
  574.  
  575.  
  576. void
  577. TWindow::AdjustMenusAfterMenuSelection(void)
  578.     {
  579.     }
  580.  
  581.  
  582. Boolean
  583. TWindow::DoMenuSelection(short /* menu */, short /* item */)
  584.     {
  585.     return false;
  586.     }
  587.     
  588.  
  589. Boolean
  590. TWindow::DoMenuCommand(unsigned long menuCommand)
  591.     {
  592.     if (menuCommand == cClose)
  593.         {
  594.         if (this->CanClose())
  595.             return this->Close();
  596.         }
  597.  
  598.     return false;
  599.     }
  600.  
  601.  
  602. ///////////////////////////////////////////////////////////////////////////
  603. //
  604. //    Drag Manager callback routines which dispatch to a window’s method
  605. //
  606.  
  607. /* static */ pascal OSErr
  608. TWindow::CallDragTrackingHandler(DragTrackingMessage dragMessage,WindowRef theWindow,void * /* refCon */,DragReference theDrag)
  609.     {
  610.     TWindow *wobj = GetWindowObject(theWindow);
  611.     
  612.     if (wobj)
  613.         return(wobj->HandleDrag(dragMessage,theDrag));
  614.     else
  615.         return dragNotAcceptedErr;
  616.     }
  617.  
  618.     
  619. /* static */ pascal OSErr
  620. TWindow::CallDragReceiveHandler(WindowRef theWindow,void * /* refCon */,DragReference theDrag)
  621.     {
  622.     TWindow *wobj = GetWindowObject(theWindow);
  623.     
  624.     if (wobj)
  625.         return(wobj->HandleDrop(theDrag));
  626.     else
  627.         return dragNotAcceptedErr;
  628.     }
  629.  
  630.  
  631. OSErr
  632. TWindow::HandleDrag(DragTrackingMessage dragMessage,DragReference theDrag)
  633.     {
  634.     OSErr    result = dragNotAcceptedErr;
  635.     
  636.     switch (dragMessage)
  637.         {
  638.         case    dragTrackingEnterWindow:
  639.             result = this->DragEnterWindow(theDrag);
  640.             break;
  641.         
  642.         case    dragTrackingInWindow:
  643.             result = this->DragInWindow(theDrag);
  644.             break;
  645.             
  646.         case    dragTrackingLeaveWindow:
  647.             result = this->DragLeaveWindow(theDrag);
  648.             break;
  649.             
  650.         default:
  651.             break;
  652.         }
  653.  
  654.     return result;
  655.     }
  656.     
  657.  
  658. OSErr
  659. TWindow::HandleDrop(DragReference /* theDrag */)
  660.     {
  661.     return dragNotAcceptedErr;
  662.     }
  663.  
  664.  
  665. OSErr
  666. TWindow::DragEnterWindow(DragReference /* theDrag */)
  667.     {
  668.     return dragNotAcceptedErr;
  669.     }
  670.  
  671.  
  672. OSErr
  673. TWindow::DragInWindow(DragReference /* theDrag */)
  674.     {
  675.     return dragNotAcceptedErr;
  676.     }
  677.  
  678.  
  679. OSErr
  680. TWindow::DragLeaveWindow(DragReference /* theDrag */)
  681.     {
  682.     return dragNotAcceptedErr;
  683.     }
  684.  
  685.  
  686. Boolean
  687. TWindow::IsPointInContentRgn( Point pt )
  688.     {
  689.     RgnHandle    tempRgn = NewRgn();
  690.  
  691.     GetWindowContentRgn(fWindow, tempRgn);
  692.     Boolean result = PtInRgn( pt, tempRgn );
  693.  
  694.     DisposeRgn(tempRgn);
  695.  
  696.     return result;
  697.     }
  698.  
  699.  
  700. Boolean
  701. TWindow::IsDragInContentRgn( DragReference dragRef )
  702.     {
  703.     Point    globalMouse;
  704.     OSErr    err;
  705.     
  706.     err = GetDragMouse( dragRef, &globalMouse, 0L );
  707.     
  708.     if ( err == noErr )
  709.         return( this->IsPointInContentRgn( globalMouse ) );
  710.     else
  711.         return( false );
  712.     }
  713.  
  714.  
  715. Rect
  716. TWindow::GetContentsBounds(void)
  717.     {
  718.     RgnHandle    tempRgn = NewRgn();
  719.     Rect        r;
  720.  
  721.     GetWindowContentRgn(fWindow, tempRgn);
  722.     r = (**tempRgn).rgnBBox;
  723.  
  724.     DisposeRgn(tempRgn);
  725.     return r;
  726.     }
  727.  
  728.  
  729. ////////////////////////////////////////////////////////////////////////
  730. //
  731. //    Utility functions
  732. //
  733.  
  734. TWindow *
  735. GetWindowObject(WindowRef aWindow)
  736.     {
  737.     short    wKind;
  738.     
  739.     if (aWindow != nil)
  740.         {
  741.         wKind = GetWindowKind ( aWindow );
  742.  
  743.         if (wKind >= userKind)
  744.             {
  745.             //    All windowKinds >= userKind are based upon TWindow
  746.  
  747.             return (TWindow *) GetWRefCon(aWindow);
  748.             }
  749.         }
  750.     return (TWindow *) nil;
  751.     }
  752.  
  753.  
  754.  
  755.  
  756. /* static */ WindowRef
  757. TWindow::GetNewWindow(short windowID, void *wStorage, WindowRef behind)
  758.     {
  759.     if (gHasColorQuickdraw)
  760.         return GetNewCWindow(windowID,wStorage,behind);
  761.     else
  762.         return GetNewWindow(windowID,wStorage,behind);
  763.     }
  764.  
  765.  
  766. /* static */ WindowRef
  767. TWindow::NewWindow(void *wStorage, const Rect *boundsRect, ConstStr255Param title, Boolean visible, short theProc, WindowRef behind, Boolean goAwayFlag, long refCon)
  768.     {
  769.     if (gHasColorQuickdraw)
  770.         return NewCWindow(wStorage,boundsRect,title,visible,theProc,behind,goAwayFlag,refCon);
  771.     else
  772.         return NewWindow(wStorage,boundsRect,title,visible,theProc,behind,goAwayFlag,refCon);
  773.     }
  774.  
  775.  
  776. /* static */  void
  777. TWindow::DrawGrowIcon(WindowRef aWindow)
  778.     {
  779.     TGraphicsContext    graphicsContext((GrafPtr) aWindow);
  780.     Rect                growBoxRect;
  781.  
  782.     //    clip to just the bottom right corner of the window
  783.  
  784.     growBoxRect = GetWindowPort(aWindow)->portRect;
  785.     growBoxRect.top    = growBoxRect.bottom - kScrollbarWidth + 1;
  786.     growBoxRect.left= growBoxRect.right - kScrollbarWidth + 1;
  787.     ClipRect(&growBoxRect);
  788.  
  789.     ::DrawGrowIcon(aWindow);
  790.     }
  791.     
  792.  
  793. ///////////////////////////////////////////////////////////////////////////
  794. //
  795. //    WindowList functions
  796. //
  797.  
  798.  
  799. /* static */ WindowRef
  800. TWindow::FrontNonFloatingWindow()
  801.     {
  802.     WindowRef    aWindow = LMGetWindowList();
  803.     
  804.     //    Loop through window list until we find a modal or normal window,
  805.     //    while skipping over invisible and/or floating windows
  806.  
  807.     while (aWindow != NULL)
  808.         {
  809.         if (IsWindowVisible(aWindow))
  810.             {
  811.             if (GetWindowKind(aWindow) != kFloatingWindow)
  812.                 break;
  813.             }
  814.  
  815.         aWindow = GetNextWindow(aWindow);
  816.         }
  817.         
  818.     return aWindow;
  819.     }
  820.  
  821.  
  822. /* static */ WindowRef
  823. TWindow::FrontModalWindow()
  824.     {
  825.     WindowRef    aWindow = LMGetWindowList();
  826.  
  827.     //    Loop through visible windows until we find a visible modal window
  828.     //    or we get to another kind of window
  829.  
  830.     while ((aWindow != NULL) && (GetWindowKind(aWindow) == kModalWindow))
  831.         {
  832.         if (IsWindowVisible(aWindow))
  833.             return aWindow;
  834.  
  835.         aWindow = GetNextWindow ( aWindow );
  836.         }
  837.  
  838.     return NULL;
  839.     }
  840.  
  841.  
  842. /* static */ WindowRef
  843. TWindow::LastModalWindow()
  844.     {
  845.     WindowRef    aWindow        = LMGetWindowList();
  846.     WindowRef    lastModal    = (WindowRef) kNoModalWindows;
  847.     SInt16        wKind;
  848.     
  849.     while ((aWindow != NULL) && ((wKind = GetWindowKind(aWindow)) == kModalWindow))
  850.         {
  851.         if (IsWindowVisible(aWindow) && (wKind == kModalWindow))
  852.             lastModal = aWindow;
  853.  
  854.         aWindow = GetNextWindow(aWindow);
  855.         }
  856.  
  857.     return lastModal;
  858.     }
  859.  
  860.  
  861. /* static */ WindowRef
  862. TWindow::FrontFloatingWindow()
  863.     {
  864.     WindowRef    aWindow = LMGetWindowList();
  865.     SInt16        wKind;
  866.  
  867.     //    Loop through visible windows until we find a visible floating window
  868.     //    or we get to another kind of window
  869.  
  870.     while ((aWindow != NULL) && ((wKind = GetWindowKind(aWindow)) <= kFloatingWindow))
  871.         {
  872.         if (IsWindowVisible(aWindow) && (wKind == kFloatingWindow))
  873.             return aWindow;
  874.  
  875.         aWindow = GetNextWindow ( aWindow );
  876.         }
  877.  
  878.     return NULL;
  879.     }
  880.  
  881.  
  882. /* static */ WindowRef
  883. TWindow::LastFloatingWindow()
  884.     {
  885.     WindowRef    aWindow        = LMGetWindowList();
  886.     WindowRef    lastFloater = (WindowRef) kNoFloatingWindows;
  887.     SInt16        wKind;
  888.     
  889.     while ((aWindow != NULL) && ((wKind = GetWindowKind(aWindow)) <= kFloatingWindow))
  890.         {
  891.         if (IsWindowVisible(aWindow) && (wKind == kFloatingWindow))
  892.             lastFloater = aWindow;
  893.  
  894.         aWindow = GetNextWindow(aWindow);
  895.         }
  896.  
  897.     return lastFloater;
  898.     }
  899.  
  900.  
  901. /* static */ WindowRef
  902. TWindow::FrontNormalWindow()
  903.     {
  904.     WindowRef    aWindow = LMGetWindowList();
  905.     SInt16        wKind;
  906.  
  907.     //    Loop through visible windows until we find a visible floating window
  908.     //    or we get to another kind of window
  909.  
  910.     while ((aWindow != NULL) && ((wKind = GetWindowKind(aWindow)) <= kNormalWindow))
  911.         {
  912.         if (IsWindowVisible(aWindow) && (wKind == kNormalWindow))
  913.             return aWindow;
  914.  
  915.         aWindow = GetNextWindow ( aWindow );
  916.         }
  917.  
  918.     return NULL;
  919.     }
  920.  
  921.  
  922.  
  923. /* static */ void
  924. TWindow::HiliteAndActivateWindow(WindowRef aWindow,Boolean active)
  925.     {
  926.     GrafPtr        oldPort;
  927.     TWindow    *    wobj = GetWindowObject(aWindow);
  928.     
  929.     if (aWindow)
  930.         {
  931.         ::HiliteWindow(aWindow,active);
  932.  
  933.         if (wobj != nil)
  934.             {
  935.             GetPort(&oldPort);
  936.             SetPortWindowPort ( aWindow );
  937.             wobj->Activate(active);
  938.             SetPort(oldPort);
  939.             }    
  940.         }
  941.     }
  942.  
  943.  
  944. /* static */ void
  945. TWindow::SuspendResumeWindows(Boolean resuming)
  946.     {
  947.     //    When we suspend/resume, hide/show all the visible floaters
  948.     
  949.     HiliteShowHideFloatingWindows(resuming,true);
  950.     }
  951.  
  952.  
  953. /* static */ void
  954. TWindow::EnterModalState()
  955.     {
  956.     //    When we display a modal dialog, we need to unhighlight
  957.     //    all visible floaters. We also need to re-hilite them
  958.     //    afterwards.
  959.  
  960.     if (fgModalState++ == 0)
  961.         HiliteShowHideFloatingWindows(false,false);
  962.  
  963.     TMenuBar::EnterModalState();
  964.     }
  965.  
  966.  
  967. /* static */ void
  968. TWindow::ExitModalState()
  969.     {
  970.     //    When we display a modal dialog, we need to unhighlight
  971.     //    all visible floaters. We also need to re-hilite them
  972.     //    afterwards.
  973.  
  974.     if (--fgModalState == 0)    
  975.         HiliteShowHideFloatingWindows(true,false);
  976.  
  977.     TMenuBar::ExitModalState();
  978.     }
  979.  
  980.  
  981. void
  982. HiliteShowHideFloatingWindows(Boolean hiliting,Boolean dohiding)
  983.     {
  984.     WindowRef    aWindow;
  985.     TWindow *    wobj;
  986.     
  987.     TWindow::HiliteAndActivateWindow(TWindow::FrontNonFloatingWindow(),hiliting);
  988.  
  989.     aWindow = LMGetWindowList();
  990.     while ( aWindow != nil && GetWindowKind ( aWindow ) == TWindow::kFloatingWindow )
  991.         {
  992.         wobj = GetWindowObject ( aWindow );
  993.         
  994.         //    If we are hiding or showing, only hide/show windows
  995.         //    that were visible to begin with.
  996.         
  997.         //    NOTE:    We use our copy of the visible flag so we can
  998.         //            automatically show floaters on a resume event.
  999.         
  1000.         //    NOTE:    Since this isn’t a method of TWindow, we don’t
  1001.         //            really need the “::” on ShowHide, but as long
  1002.         //            as we’re trying to avoid ambiguity.
  1003.         
  1004.         if (dohiding && (wobj != nil) && (wobj->IsVisible()))
  1005.             ::ShowHide(aWindow,hiliting);
  1006.             
  1007.         //    All floaters are hilited if any floater is hilited
  1008.  
  1009.         HiliteWindow( aWindow,hiliting);
  1010.         aWindow = GetNextWindow ( aWindow );
  1011.         }
  1012.     }
  1013.  
  1014.  
  1015. ///////////////////////////////////////////////////////////////////////////
  1016. //
  1017. //    Routines used for dealing with windows and multiple screens
  1018. //
  1019.  
  1020. pascal void
  1021. CalculateWindowAreaOnDevice(short /* depth */,short /* deviceFlags */,GDHandle targetDevice,long userData)
  1022.     {
  1023.     CalcWindowAreaDeviceLoopUserData *    deviceLoopDataPtr;
  1024.     long                                windowAreaOnThisScreen;
  1025.     Rect                                windowRectOnThisScreen;
  1026.     
  1027.     deviceLoopDataPtr = (CalcWindowAreaDeviceLoopUserData *) userData;
  1028.  
  1029.     SectRect(&deviceLoopDataPtr->fWindowBounds, &(**targetDevice).gdRect,&windowRectOnThisScreen);
  1030.     OffsetRect(&windowRectOnThisScreen,-windowRectOnThisScreen.left,-windowRectOnThisScreen.top);
  1031.     windowAreaOnThisScreen = windowRectOnThisScreen.right * windowRectOnThisScreen.bottom;
  1032.  
  1033.     if (windowAreaOnThisScreen > deviceLoopDataPtr->fLargestArea)
  1034.         {
  1035.         deviceLoopDataPtr->fLargestArea = windowAreaOnThisScreen;
  1036.         deviceLoopDataPtr->fScreenWithLargestPartOfWindow = targetDevice;
  1037.         }
  1038.     }
  1039.  
  1040.  
  1041. DeviceLoopDrawingUPP CallCalcWindowAreaOnDevice = NewDeviceLoopDrawingProc(&CalculateWindowAreaOnDevice);
  1042.  
  1043.  
  1044. void
  1045. FindScreenRectWithLargestPartOfWindow(WindowRef aWindow,Rect *theBestScreenRect,GDHandle * theBestDevice)
  1046.     {
  1047.     RgnHandle                            copyOfWindowStrucRgn;
  1048.     CalcWindowAreaDeviceLoopUserData    deviceLoopData;
  1049.  
  1050.     //    Use DeviceLoop to find out what GDevice contains the largest
  1051.     //    portion of the supplied window.
  1052.     //
  1053.     //    NOTE:    Assumes thePort == the Window Manager Port because we using
  1054.     //            the window strucRgn, not contRgn.
  1055.  
  1056.     deviceLoopData.fScreenWithLargestPartOfWindow = nil;
  1057.     deviceLoopData.fLargestArea = -1;
  1058.  
  1059.     RgnHandle    tempRgn = NewRgn ();
  1060.     GetWindowContentRgn ( aWindow, tempRgn );
  1061.     deviceLoopData.fWindowBounds = (**tempRgn).rgnBBox;
  1062.     DisposeRgn ( tempRgn );
  1063.  
  1064.     copyOfWindowStrucRgn = NewRgn();
  1065.     GetWindowStructureRgn ( aWindow, copyOfWindowStrucRgn );
  1066.  
  1067.     DeviceLoop(copyOfWindowStrucRgn,CallCalcWindowAreaOnDevice,(long) &deviceLoopData,singleDevices);    
  1068.  
  1069.     DisposeRgn(copyOfWindowStrucRgn);
  1070.     
  1071.     *theBestDevice = deviceLoopData.fScreenWithLargestPartOfWindow;
  1072.     *theBestScreenRect = (**(deviceLoopData.fScreenWithLargestPartOfWindow)).gdRect;
  1073.  
  1074.     //    Leave some space around the edges of the screen so window look good, AND
  1075.     //    if the best device is the main screen, leave space for the Menubar
  1076.     
  1077.     InsetRect(theBestScreenRect,kScreenEdgeSlop,kScreenEdgeSlop);
  1078.     if (GetMainDevice() == deviceLoopData.fScreenWithLargestPartOfWindow)
  1079.         theBestScreenRect->top += GetMBarHeight();
  1080.     }
  1081.  
  1082.  
  1083.